package meblog.online.server.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import lombok.extern.slf4j.Slf4j;
import meblog.online.server.config.SystemException;
import meblog.online.server.entity.Server;
import meblog.online.server.message.ServerInsertVo;
import meblog.online.server.message.ServerSimpleVo;
import meblog.online.server.message.ServerUpdateVo;
import meblog.online.server.service.ChannelService;
import meblog.online.server.service.ServerService;
import meblog.online.server.mapper.ServerMapper;
import meblog.online.server.utils.PageMessage;
import meblog.online.server.utils.ResultCode;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author yuelong
* @description 针对表【m_server(服务器列表)】的数据库操作Service实现
* @createDate 2022-11-22 20:27:58
*/
@Slf4j
@Service
@Transactional(rollbackFor = Exception.class)
public class ServerServiceImpl implements ServerService {

    private final ServerMapper serverMapper;

    private final ChannelService channelService;

    public ServerServiceImpl(ServerMapper serverMapper, ChannelService channelService) {
        this.serverMapper = serverMapper;
        this.channelService = channelService;
    }

    @Override
    public ServerSimpleVo insertServer(ServerInsertVo insertVo) {
        boolean exists = serverMapper.exists(new LambdaQueryWrapper<Server>()
                .eq(Server::getTitle, insertVo.getTitle())
                .eq(Server::getCanView, true)
        );
        if (exists) {
            throw new SystemException(ResultCode.DATA_EXIST);
        }
        Server server = insertVo.formBuild();
        serverMapper.insert(server);
        return ServerSimpleVo.build(server);
    }

    @Override
    public PageMessage<ServerSimpleVo> list(Long page, Long limit) {
        Page<Server> pages = serverMapper.selectPage(
                new Page<>(page, limit),
                new LambdaQueryWrapper<Server>().eq(Server::getCanView, true)
        );
        PageMessage<ServerSimpleVo> result = new PageMessage<>(page, limit, pages.getTotal());
        if (pages.getRecords().isEmpty()) {
            result.setRecords(new ArrayList<>());
        } else {
            List<ServerSimpleVo> collect = pages.getRecords()
                    .stream()
                    .map(ServerSimpleVo::build)
                    .collect(Collectors.toList());
            result.setRecords(collect);
        }
        return result;
    }

    @Override
    public ServerSimpleVo copy(Integer id) {
        Server server = serverMapper.selectById(id);
        if (Objects.isNull(server) || !server.getCanView()) {
            throw new SystemException(ResultCode.DATA_NOT_EXIST);
        }
        String newTitle = server.getTitle() + "_copy";
        Long count = serverMapper.selectCount(new LambdaQueryWrapper<Server>().likeLeft(Server::getTitle, newTitle + "%"));
        server.setId(null)
                .setTitle(newTitle + "_" + (count + 1))
                .setCreateTime(LocalDateTime.now())
                .setUpdateTime(LocalDateTime.now());
        serverMapper.insert(server);
        return ServerSimpleVo.build(server);
    }

    @Override
    public Boolean delete(String ids) {
        List<Integer> list = Arrays.stream(ids.split(",")).map(Integer::parseInt).toList();
        serverMapper.batchLogicDelete(list);
        return true;
    }

    @Override
    public Server one(Integer id) {
        Server server = serverMapper.selectById(id);
        if (Objects.isNull(server) || !server.getCanView()) {
            throw new SystemException(ResultCode.DATA_NOT_EXIST);
        }
        return server;
    }

    @Override
    public ServerSimpleVo update(ServerUpdateVo param) {
        Server server = one(param.getId());
        if (serverMapper.exists(new LambdaQueryWrapper<Server>().eq(Server::getTitle, param.getTitle()))) {
            throw new SystemException(ResultCode.SERVER_TITLE_EXIST);
        }
        server.setPassword(param.getPassword())
                .setPassword(param.getUsername())
                .setHost(param.getHost())
                .setBrief(param.getBrief())
                .setPort(param.getPort())
                .setTitle(param.getTitle())
                .setUpdateTime(LocalDateTime.now());
        serverMapper.updateById(server);
        return ServerSimpleVo.build(server);
    }

    @Override
    public String ping(Integer id) {
        Server server = serverMapper.selectOne(new LambdaQueryWrapper<Server>().eq(Server::getId, id).eq(Server::getCanView, true));
        if (Objects.isNull(server)) {
            throw new SystemException(ResultCode.DATA_NOT_EXIST);
        }
        // 连接远程服务器
        JSch jsch = new JSch();
        try {
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            Session session = jsch.getSession(server.getUsername(), server.getHost(), server.getPort());
            session.setConfig(config);
            session.setPassword(server.getPassword());
            session.connect(30000);

            Channel shell = session.openChannel("shell");
            shell.connect(30000);
            new Thread(() -> {
                try {
                    InputStream inputStream = shell.getInputStream();
                    //循环读取
                    byte[] buffer = new byte[1024];
                    int i = 0;
                    //如果没有数据来，线程会一直阻塞在这个地方等待数据。
                    while ((i = inputStream.read(buffer)) != -1) {
                        log.info("{}", new String(Arrays.copyOfRange(buffer, 0, i)));
                    }
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }, "test").start();

            try {
                OutputStream outputStream = shell.getOutputStream();
                outputStream.write("ls -al\n".getBytes(StandardCharsets.UTF_8));
                outputStream.flush();
            } catch (Exception e) {

            }

        } catch (JSchException e) {
            log.error("连接服务器失败:{}", e.getMessage());
            throw new SystemException(ResultCode.SERVER_CONNECT_FAIL);
        }
        return "测试连接成功";
    }

    @Override
    public Boolean cmd(String cmd) {
        channelService.terminalCommand(null, cmd);
        return true;
    }
}




